#include "../logs/kaizi.h"
#include <vector>
#include <thread>
#include <chrono> //提供计时的操作
// 封装一个接口，传入日志器名称，线程数量，日志数量，单条日志大小
void bench(const std::string &logger_name, size_t thr_count, size_t msg_count, size_t msg_len)
{
    // 1、获取日志器
    kaizi::Logger::ptr logger = kaizi::getLogger(logger_name);
    if (logger.get() == nullptr)
        return; // 没有指定的日志器我们就进行退出了
    std::cout << "测试日志" << msg_count << "条,总大小：" << (msg_count * msg_len) / 1024 << "KB\n"
              << std::endl;
    // 2、组织指定长度的日志消息---下面是构建了一条指定长度的字符串
    std::string msg(msg_len - 1, 'A'); // 少一个字节是为了给末尾添加换行
    // 3、创建指定数量的线程
    std::vector<std::thread> threads;
    std::vector<double> const_arry(thr_count);
    size_t msg_per_thr = msg_count / thr_count; // 总日志数量除以线程数量就是每个线程输出的日志数量
    for (int i = 0; i < thr_count; i++)
    {
        // emplace_back是构造并且插入元素到末尾
        threads.emplace_back([&, i]()
                             {
            //4、线程函数内部开始计时
            auto start=std::chrono::high_resolution_clock::now();//计时开始
            //5、开始循环写日志
            for(int j=0;j<msg_per_thr;j++)
            {
                logger->fatal("%s",msg.c_str());//进行循环写入操作
            }
            //6、线程函数内部结束计时
            auto end=std::chrono::high_resolution_clock::now();//计时结束
            std::chrono::duration<double> cost=end-start;//计算耗时
            //计算并且输出耗时多少秒
            const_arry[i]=cost.count();
            std::cout<<"线程"<<i<<":"<<"\t输出数量:"<<msg_per_thr<<"耗时:"<<cost.count()<<"s"<<std::endl; });
    }
    for (int i = 0; i < thr_count; i++)
    {
        threads[i].join(); // 等待所有线程退出
    }
    // 7、计算总耗时：在多线程中，每个线程都会耗费时间，但是线程是并发处理的，所以耗时最高的那个就是总时间
    double max_cost = const_arry[0];
    for (int i = 0; i < thr_count; i++)
        max_cost = max_cost < const_arry[i] ? const_arry[i] : max_cost;
    size_t msg_per_sec = msg_count / max_cost;                       // 每秒耗时
    size_t size_per_sec = (msg_len * msg_count) / (max_cost * 1024); // 每秒输出日志大小

    // 8、进行输出打印
    std::cout << "总耗时：" << max_cost << "s\n";
    std::cout << "每秒输出日志数量：" << msg_per_sec << "条\n"<< std::endl;
    std::cout << "每秒输出日志大小：" << size_per_sec << "KB\n"<< std::endl;
}

// 同步日志测试
void sync_bench()
{

    std::unique_ptr<kaizi::LoggerBuilder> builder(new kaizi::GlobalLoggerBuilder());

    // 设置日志器名称
    builder->buildLoggerName("sync_logger");
    // 设置日志格式，[时间][级别][进程ID] 消息换行
    builder->buildFormatter("%m%n");
    // 设置日志器类型为同步日志器
    builder->buildLoggerType(kaizi::LoggerType::LOGGER_SYNC);

    // 添加 FileSink，日志输出到 ./logfile/sync.log 文件
    builder->buildSink<kaizi::FileSink>("./logfile/sync.log");

    // 构建日志器
    auto logger = builder->build();
    // 日志器名称，线程数量，日志数量，单条日志大小，这里是100字节大小
    // 单线程测试
    bench("sync_logger", 3, 1000000, 100);
    // 多线程测试
    //bench("sync_logger", 3, 1000000, 100);
}
// 异步日志测试
void async_bench()
{

    std::unique_ptr<kaizi::LoggerBuilder> builder(new kaizi::GlobalLoggerBuilder());

    // 设置日志器名称
    builder->buildLoggerName("async_logger");
    // 设置日志格式，[时间][级别][进程ID] 消息换行
    builder->buildFormatter("%m%n");
    // 设置日志器类型为同步日志器
    builder->buildLoggerType(kaizi::LoggerType::LOGGER_ASYNC);

    //开启非安全模式
    builder->buildEnableUnSafeAsync();
    //将我们实际落地时间排除
    // 添加 FileSink，日志输出到 ./logfile/sync.log 文件
    builder->buildSink<kaizi::FileSink>("./logfile/async.log");

    // 构建日志器
    auto logger = builder->build();
    // 日志器名称，线程数量，日志数量，单条日志大小，这里是100字节大小
    // 单线程测试
    bench("async_logger", 10, 2000000, 100);
    // 多线程测试
    //bench("async_logger", 3, 1000000, 100);
}


int main()
{
    async_bench();
    return 0;
}
